/*
 ** writen by hanv
 ** n2.vietha@gmail.com
 */
package vn.vng.research.fsd.search;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import vn.vng.research.fsd.SearchApplication;
import vn.vng.research.fsd.da.ProfilesDA;
import vn.vng.research.fsd.da.SchoolRefinerDA;
import vn.vng.research.fsd.data.FacetCollector;
import vn.vng.research.fsd.data.FacetedTopDocs;
import vn.vng.research.fsd.data.SearchResult;
import vn.vng.research.fsd.data.User;
import vn.vng.research.fsd.services.thrift.TResult;
import vn.vng.research.fsd.services.thrift.TSchool;
import vn.vng.research.fsd.services.thrift.TUser;
import vn.vng.research.fsd.utils.SchoolCountComparator;
import vn.vng.research.fsd.utils.ScoreDocComparator;

public class FacetedSearcher {
	public static SearchResult matchAndGroup(String queries, int hitsPerPage, int pageNumber, int schoolID) throws Exception {

		Date time = new Date();

		//
		// SEARCH INIT
		//
		IndexSearcher searcher = new IndexSearcher(FSDirectory.open(new File(
				ProfilesDA.getINDEX_PATH())));
		Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_31);

		String field = "displayname";
		QueryParser parser = new QueryParser(Version.LUCENE_31, field, analyzer);

		
		Query query = parser.parse(queries);

		System.out.println("Started searching for: " + query.toString(field));
		System.out.println("Rewritten Query: " + query.rewrite(null).toString());
		long start = System.currentTimeMillis();

		//
		// MATCHING
		//
		FacetCollector facetCollector = new FacetCollector();

		if (schoolID>SchoolRefinerDA.UNKNOWN_ID){
			Filter filter = NumericRangeFilter.newIntRange("education", schoolID, schoolID, true, true);
			searcher.search(query,filter,facetCollector);
		} else searcher.search(query,facetCollector);
		
		FacetedTopDocs topDocs = facetCollector.getTopDocs();
		long end = System.currentTimeMillis();

		long matchingDelay = end - start;
		System.out.println("Found " + topDocs.getTotalHits()
				+ " profile(s) match " /*+ query.rewrite(null).toString()*/
				+ " after " + matchingDelay + "ms.");

		System.out.println("Started grouping school in results");
		start = System.currentTimeMillis();

		if (topDocs.getTotalHits() <= 0)
			return null;

		//
		// GROUPING SCHOOL
		//
		
		Collections.sort(topDocs.getScoreDocuments(), new ScoreDocComparator());
		Collections.sort(topDocs.getSchoolLs(), new SchoolCountComparator());
		
		int maxPage = topDocs.getTotalHits()/hitsPerPage+1;
		
		pageNumber = Math.min(pageNumber, maxPage);
		
		for (int i=((pageNumber-1)*hitsPerPage); i<Math.min(topDocs.getTotalHits(),((pageNumber)*hitsPerPage));i++){
			Document doc = searcher.doc(topDocs.getScoreDocuments().get(i).doc);

			int uid = Integer.parseInt(doc.get("uid"));
			String username = doc.get("username");
			String email = doc.get("email");
			String displayname = doc.get("displayname");
			int education = Integer.parseInt(doc.get("education"));

			TUser user = new TUser(uid, username, email, displayname, education);
			topDocs.getProfiles().add(user);
		}

		end = System.currentTimeMillis();

		long groupSchoolDelay = end - start;
		System.out.println("Scan " + topDocs.getProfiles().size()
				+ " profile(s) completed, " + (topDocs.getSchoolLs().size())
				+ " school(s) found after " + groupSchoolDelay + "ms.");

		SearchResult searchResult = new SearchResult(queries, topDocs, time,
				matchingDelay + groupSchoolDelay);
	
		return searchResult;
	}

	public static TResult search(String queries, int hitsPerPage, int pageNumber) throws Exception {
		long start = System.currentTimeMillis();
		SearchResult searchResult = matchAndGroup(queries, hitsPerPage, pageNumber, -1);
		
		if (searchResult == null)
			return new TResult(-1, null, null, 0);
		//SearchApplication.cache.put(searchResult);

		List<TUser> userLs = searchResult.getTopDocs().getProfiles();
		
		List<TSchool> schoolLs = searchResult.getTopDocs().getSchoolLs();
		
		TResult tResult = new TResult(searchResult.getId(), userLs, schoolLs,searchResult.getTopDocs().getTotalHits());
		long end = System.currentTimeMillis();
		System.out.println("Server excuting time: " + (end-start)+"ms.");
		return tResult;
	}

	public static TResult facet(long searchid, String queries,
			List<Integer> schoolsid, int hitsPerPage, int pageNumber) throws Exception {
		long start = System.currentTimeMillis();
//		SearchResult searchResult = SearchApplication.cache.get(searchid);
//		if (searchResult == null) {
//			searchResult = matchAndGroup(queries, hitsPerPage, pageNumber, schoolsid.get(0));
//			if (searchResult == null)
//				return new TResult(-1, null, null, 0);
//			SearchApplication.cache.put(searchResult);
//		}

		SearchResult searchResult = matchAndGroup(queries, hitsPerPage, pageNumber, schoolsid.get(0));
		if (searchResult == null)
			return new TResult(-1, null, null, 0);
//		FacetedTopDocs topDocs = searchResult.getTopDocs();
		List<TUser> userLs = searchResult.getTopDocs().getProfiles();
		List<TSchool> schoolLs = searchResult.getTopDocs().getSchoolLs();
		/*List<TUser> userLs = new LinkedList<TUser>();
		//long start = System.currentTimeMillis();		
		for (int j = 0; j < schoolsid.size(); j++) {
			List<TUser> profiles = topDocs.getSchoolGroups().get(
					schoolsid.get(j));
			if (profiles == null)
				continue;
			userLs.addAll(profiles);
		}
		//long end = System.currentTimeMillis();
		//System.out.println("Facet - Create users list took " + (end-start)+"ms.");
		
		if (userLs.size() <= 0)
			return new TResult(-1, null, null);

		//start = System.currentTimeMillis();
		List<TSchool> schoolLs = new LinkedList<TSchool>();

		for (int i = 0; i < schoolsid.size(); i++) {
			int id = schoolsid.get(i);
			int count = 0;
			List<TUser> profiles = topDocs.getSchoolGroups().get(id);
			if (profiles != null)
				count = profiles.size();
			String name = SchoolRefinerDA.getSchoolName(id);
			
			TSchool tSchool = new TSchool(id, name, count);
			schoolLs.add(tSchool);
		}*/
		//end = System.currentTimeMillis();
		//System.out.println("Facet - Create schools list took " + (end-start)+ "ms.");
		
		TResult tResult = new TResult(searchResult.getId(), userLs, schoolLs, searchResult.getTopDocs().getTotalHits());
		long end = System.currentTimeMillis();
		System.out.println("Server excuting time: " + (end-start)+"ms.");
		return tResult;
	}

}
